home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 2000 #1
/
Amiga Plus CD - 2000 - No. 1.iso
/
Tools
/
Dev
/
AmigaAMP-PDK
/
WideSpectrum.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-12-03
|
15KB
|
466 lines
/*****************************************************************************/
/* */
/* AmigaAMP Wide Spectrometer Plugin 1.3 */
/* */
/* Written August 1999 by Thomas Wenzel */
/* */
/*****************************************************************************/
/* */
/* This is an example how to write your own AmigaAMP visualisation plugin */
/* To make it as easy as possible all plugins are normal AmigaDOS */
/* executables which can be launched and stopped at any time. */
/* */
/* This sourcecode and executable are free for non-commercial use only! */
/* */
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <dos/dostags.h>
#include <graphics/gfxbase.h>
#include "TrackInfo.h" // new in v1.2
WORD PluginInit(void);
void PluginExit(void);
void PluginLoop(void);
void ShowRequester(char *Text, char *Button);
/***************************************************************************/
/* This is the global variables section. Don't change anything here unless */
/* you know what you're doing! */
/***************************************************************************/
BYTE PluginSignal, InfoSignal;
ULONG PluginMask, InfoMask;
WORD Accepted;
struct Process *PluginTask;
struct MsgPort *PluginMP;
struct MsgPort *PluginRP;
struct TrackInfo *tinfo; /* New: v1.2 */
UWORD *PluginRawL;
UWORD *PluginRawR;
WORD *PluginSamples;
UWORD *SpecRawL;
UWORD *SpecRawR;
WORD *SampleRaw;
struct PluginMessage {
struct Message msg;
ULONG PluginMask;
struct Process *PluginTask;
UWORD **SpecRawL;
UWORD **SpecRawR;
WORD Accepted; /* v1.3: Don't use BOOL any more because */
WORD reserved0; /* it causes alignment problems! */
/* All data beyond this point is new for v1.2. */
/* AmigaAMP v2.5 and up will detect this new data and act accordingly. */
/* Older versions of AmigaAMP will simply ignore it. */
ULONG InfoMask;
struct TrackInfo **tinfo;
ULONG reserved; // always set to 0
/* All data beyond this point is new for v1.3. */
/* AmigaAMP v2.7 and up will detect this new data and act accordingly. */
/* Older versions of AmigaAMP will simply ignore it. */
WORD **SampleRaw;
};
/***************************************************************************/
/* This is the main part. Again, don't change anything here if you haven't */
/* got a very good reason to do so! */
/***************************************************************************/
void main(void) {
struct PluginMessage *PluginMsg;
struct PluginMessage *ReplyMsg;
/* Allocate all user resources */
if(PluginInit()) {
/* Check if a plugin capable instance of AmigaAMP is running */
if(PluginMP=FindPort("AmigaAMP plugin port")) {
/* Allocate a sigbit for receiving signals FROM AmigaAMP */
PluginSignal = AllocSignal(-1);
InfoSignal = AllocSignal(-1); /* New: v1.2 */
PluginTask = (struct Process *)FindTask(NULL);
if(PluginSignal != -1 && InfoSignal != -1) {
PluginMask = 1L << PluginSignal;
InfoMask = 1L << InfoSignal;
/* Allocate a message and reply port for sending messages TO AmigaAMP */
PluginMsg=AllocVec(sizeof(struct PluginMessage), MEMF_PUBLIC|MEMF_CLEAR);
PluginRP=CreatePort(0,0);
/* Tell AmigaAMP all the details it needs to know */
PluginMsg->msg.mn_Node.ln_Type = NT_MESSAGE;
PluginMsg->msg.mn_Length = sizeof(struct PluginMessage);
PluginMsg->msg.mn_ReplyPort = PluginRP;
PluginMsg->PluginMask = PluginMask;
PluginMsg->PluginTask = PluginTask;
PluginMsg->SpecRawL = &SpecRawL;
PluginMsg->SpecRawR = &SpecRawR;
PluginMsg->InfoMask = InfoMask; /* New: v1.2 */
PluginMsg->tinfo = &tinfo; /* New: v1.2 */
PluginMsg->reserved = 0; /* New: v1.2 */
PluginMsg->SampleRaw = &SampleRaw; /* New: v1.3 */
PutMsg(PluginMP, (struct Message *)PluginMsg);
/* Wait for a reply */
WaitPort(PluginRP);
/* Let's see if AmigaAMP accepted our registration attempt */
if(ReplyMsg = (struct PluginMessage *)GetMsg(PluginRP)) Accepted=ReplyMsg->Accepted;
else Accepted=FALSE;
if(Accepted) {
/* If it did, start the plugin loop */
PluginLoop();
/* Tell AmigaAMP that this plugin is going down */
PluginMsg->PluginMask = NULL;
PluginMsg->PluginTask = NULL;
PluginMsg->SpecRawL = NULL;
PluginMsg->SpecRawR = NULL;
PluginMsg->InfoMask = NULL; /* New: v1.2 */
PluginMsg->tinfo = NULL; /* New: v1.2 */
PluginMsg->SampleRaw = NULL; /* New: v1.3 */
PutMsg(PluginMP, (struct Message *)PluginMsg);
/* Wait for confirmation before going on! */
WaitPort(PluginRP);
GetMsg(PluginRP);
/* Now that AmigaAMP knows that we're gone, we can quit */
}
else {
/* If AmigaAMP didn't accept us, tell the user about it */
ShowRequester("Plugin rejected by AmigaAMP!\nPerhaps there's another one running.", "Abort");
}
/* Free all resources */
FreeVec(PluginMsg);
DeletePort(PluginRP);
if(PluginSignal != -1) FreeSignal(PluginSignal);
if(InfoSignal != -1) FreeSignal(InfoSignal);
}
else {
ShowRequester("Signal allocation failure!", "Abort");
}
}
else {
ShowRequester("Could not find message port!\nAmigaAMP probably not running.", "Abort");
}
}
else {
ShowRequester("Plugin initialisation failed!", "Ok");
}
/* Free all user resources */
PluginExit();
}
/*****************************************************************************/
/* Ok, now for the individual plugin sourcecode. Everything below should be */
/* changed to your needs. */
/* Just like before, we start with the global variables section */
/*****************************************************************************/
/* Turn on some code optimizations */
#define OPTIMIZED
#define STEP 2
const char VersionString[]="\0$VER: WideSpectrometer 1.2 (27.01.99)";
struct Screen *PluginScreen = NULL;
struct Window *PluginWin = NULL;
struct RastPort *rp;
struct RastPort *tmprp;
ULONG WinMask;
UBYTE Pixel[132][512];
UBYTE Colour[128];
UBYTE ScopePen;
UBYTE PeakL[256];
UBYTE PeakR[256];
UBYTE MaxL[256];
UBYTE MaxR[256];
UWORD offx, offy;
char InfoLine[256];
/****************************************************************************/
/* This function will be called once when the plugin is started. You should */
/* allocate all needed resources here. Return TRUE if all went well. */
/****************************************************************************/
WORD PluginInit(void) {
long i;
if(GfxBase->LibNode.lib_Version < 39) {
ShowRequester("This plugin requires AmigaOS 3.0 or greater!", "Abort");
return(FALSE);
}
if(PluginWin=OpenWindowTags(NULL,
WA_Left, 20,
WA_Top, 20,
WA_InnerWidth, 512,
WA_InnerHeight, 132,
WA_Title, "AmigaAMP Wide Spectrometer Plugin 1.2",
WA_DragBar, TRUE,
WA_DepthGadget, TRUE,
WA_CloseGadget, TRUE,
WA_IDCMP, IDCMP_CLOSEWINDOW,
TAG_END)) {
WinMask = 1L << PluginWin->UserPort->mp_SigBit;
rp=PluginWin->RPort;
/* This is an attempt to make it OS3.0 compatible. */
/* Don't blame me if it doesn't work :-) */
tmprp=(struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_CHIP|MEMF_CLEAR);
CopyMem(rp, tmprp, sizeof(struct RastPort));
tmprp->Layer = NULL;
tmprp->BitMap = AllocBitMap((((512+15)>>4)<<1), 1, 8, BMF_CLEAR|BMF_DISPLAYABLE, rp->BitMap);
offx = PluginWin->BorderLeft;
offy = PluginWin->BorderTop;
if(PluginScreen=LockPubScreen(NULL)) {
for(i=0; i<64; i++) {
Colour[i] = ObtainBestPen(PluginScreen->ViewPort.ColorMap, 0xFFFFFFFF, i * 0x4000000, 0, NULL);
Colour[i+64] = ObtainBestPen(PluginScreen->ViewPort.ColorMap, 0xFFFFFFFF, 0xFFFFFFFF, i * 0x4000000, NULL);
}
ScopePen = ObtainBestPen(PluginScreen->ViewPort.ColorMap, 0x22222222, 0xFFFFFFFF, 0x2222222, NULL);
for(i=0; i<256; i++) {
PeakL[i]=0;
PeakR[i]=0;
MaxL[i]=0;
MaxR[i]=0;
}
return(TRUE);
}
}
return(FALSE);
}
/******************************************************************************/
/* This function will be called when the plugin is shut down. You should free */
/* all previously allocated resources here. */
/******************************************************************************/
void PluginExit(void) {
long i;
if(PluginScreen) for(i=0; i<128; i++) {
ReleasePen(PluginScreen->ViewPort.ColorMap, Colour[i]);
}
ReleasePen(PluginScreen->ViewPort.ColorMap, ScopePen);
if(tmprp) {
if(tmprp->BitMap) FreeBitMap(tmprp->BitMap);
FreeVec(tmprp);
}
if(PluginWin) CloseWindow(PluginWin);
if(PluginScreen) UnlockPubScreen(NULL, PluginScreen);
}
/*******************************************************************************/
/* This is the main Plugin Loop. It will receive a signal matching PluginMask */
/* each time new spectral data is ready. The data is stored in two arrays, */
/* UWORD SpecRawL[512] and UWORD SpecRawR[512]. The scale is logarithmic, i.e. */
/* 0 means below -96dB, 65535 means 0dB. Another array SampleRaw[1024] holds */
/* the current waveform. This array is not divided into left and right channel */
/* but contains interleaved stereo data, 16-bit signed just like in an AIFF or */
/* in a CDDA file. */
/* No matter how long it takes until your plugin actually processes the data, */
/* the memory referenced by the array pointers always remains valid! */
/* */
/* Your plugin loop MUST quit when it receives SIGBREAKF_CTRL_C. If you've */
/* opened a window you should react to the close gadget as well. For full */
/* screen plugins I strongly recommend checking the ESC key. */
/*******************************************************************************/
void PluginLoop(void) {
ULONG *PixelL;
UBYTE *ActPixel;
ULONG Signals;
LONG i,j,l;
WORD Sample;
UBYTE Value;
for(;;) {
/* Wait until there's something to do */
Signals=Wait(SIGBREAKF_CTRL_C | PluginMask | WinMask | InfoMask);
/* Break received -> quit at once! */
if(Signals & SIGBREAKF_CTRL_C) break;
/* Window close gadget hit -> quit as well! */
if(Signals & WinMask) {
struct IntuiMessage *imsg;
WORD done=0;
while(imsg=(struct IntuiMessage *)GetMsg(PluginWin->UserPort)) {
if(imsg->Class == IDCMP_CLOSEWINDOW) done=1;
}
if(done) break;
}
/* New data has arrived! */
if(Signals & PluginMask) {
/* Initialize the pixel array */
#ifdef OPTIMIZED
PixelL = (ULONG*)Pixel;
for(i=0; i<16896; i++) {
*PixelL++ = 0x01010101;
}
#else
for(i=0; i<512; i++) {
for(j=0; j<132; j++) {
Pixel[j][i]=1;
}
}
#endif
/* Make a backup of the data pointers */
PluginRawL = SpecRawL;
PluginRawR = SpecRawR;
PluginSamples = SampleRaw; /* New: v1.3 */
/* Process the spectral data of the left channel */
for(i=1; i<256; i+=STEP) {
/* Get the value of each spectral line to be drawn */
/* The value ranges from 0 to 65535. Our window has */
/* only room for 128 pixels so we need to scale it */
/* down. */
l=PluginRawL[512-(i<<1)]>>9;
/* Set peak- and peak-hold-values */
if(l>PeakL[i]) PeakL[i]=l;
if(l>MaxL[i]) MaxL[i]=l;
/* Draw the colourful line */
#ifdef OPTIMIZED
ActPixel=&Pixel[130][i];
for(j=0; j<MaxL[i]; j++) {
*ActPixel = Colour[j];
ActPixel -= 512;
}
#else
for(j=0; j<MaxL[i]; j++) {
Pixel[130-j][i]=Colour[j];
}
#endif
/* Draw the peak pixel */
Pixel[130-PeakL[i]][i]=2;
/* Draw the waveform pixel */
Pixel[65-(SampleRaw[i<<1]>>9)][i]=ScopePen;
/* Calculate the falloff of both peak and peak-hold */
Value=PeakL[i];
if(Value > 96) Value--;
if(Value > 64) Value--;
if(Value > 32) Value--;
if(Value > 1) Value--;
PeakL[i]=Value;
Value=MaxL[i];
if(Value > 96) Value-=4;
if(Value > 64) Value-=4;
if(Value > 32) Value-=4;
if(Value > 4) Value-=4;
if(Value > 1) Value-=1;
MaxL[i]=Value;
}
/* Process the spectral data of the right channel */
for(i=1; i<256; i+=STEP) {
l=PluginRawR[i<<1]>>9;
if(l>PeakR[i]) PeakR[i]=l;
if(l>MaxR[i]) MaxR[i]=l;
#ifdef OPTIMIZED
ActPixel=&Pixel[130][256+i];
for(j=0; j<MaxR[i]; j++) {
*ActPixel = Colour[j];
ActPixel -= 512;
}
#else
for(j=0; j<MaxR[i]; j++) {
Pixel[130-j][256+i]=Colour[j];
}
#endif
Pixel[130-PeakR[i]][256+i]=2;
Pixel[65-(SampleRaw[i<<1+1]>>9)][256+i]=ScopePen;
Value=PeakR[i];
if(Value > 96) Value--;
if(Value > 64) Value--;
if(Value > 32) Value--;
if(Value > 1) Value--;
PeakR[i]=Value;
Value=MaxR[i];
if(Value > 96) Value-=4;
if(Value > 64) Value-=4;
if(Value > 32) Value-=4;
if(Value > 4) Value-=4;
if(Value > 1) Value-=1;
MaxR[i]=Value;
}
/* Draw the image (now uses WPA8 for OS3.0 compatibility) */
// WriteChunkyPixels(rp, offx, offy, offx+511, offy+131, &Pixel[0][0], 512);
WritePixelArray8(rp, offx, offy, offx+511, offy+131, &Pixel[0][0], tmprp);
}
/* New track info has arrived! */
if(Signals & InfoMask) {
if(tinfo) {
/* process contents of tinfo here */
/* see "TrackInfo.h" for details! */
/* Example: Display the track info text */
if(tinfo->TrackInfoText) {
sprintf(InfoLine, "AmigaAMP: %s", tinfo->TrackInfoText);
SetWindowTitles(PluginWin, InfoLine, "AmigaAMP Wide Spectrometer Plugin 1.3");
}
}
}
}
}
void ShowRequester(char *Text, char *Button) {
struct EasyStruct Req;
Req.es_Title = "AmigaAMP Plugin";
Req.es_TextFormat = (UBYTE*)Text;
Req.es_GadgetFormat = (UBYTE*)Button;
EasyRequestArgs(NULL, &Req, NULL, NULL);
}